package com.spzx.channel.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.spzx.channel.service.IItemService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.api.domain.Product;
import com.spzx.product.api.domain.ProductDetails;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.vo.ItemVo;
import com.spzx.product.api.domain.vo.SkuPrice;
import com.spzx.product.api.domain.vo.SkuStockVo;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

@Service
public class ItemServiceImpl implements IItemService {

    @Autowired
    RemoteProductService remoteProductService;

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    ThreadPoolExecutor threadPoolExecutor;

    /**
     * 将远程调用6个接口任务，由同步请求(串行) 变成  异步请求(并行)  。 目的提高响应效  率即：缩短响应时间。
     *      解决方案： 线程池 + CompletableFuture
     *
     * @param skuId skuId主键
     * @return
     */
    @Override
    public ItemVo item(Long skuId) {
        //  前端 -> channel (bloomFiler -> openFegin)  -> Product(切面（ redis -> 分布式锁 -> 数据库）)
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter("sku:bloom:filter");
        if(!bloomFilter.contains(skuId)){
            throw new ServiceException("布隆过滤器中数据不存在");
        }

        ItemVo itemVo = new ItemVo();

        //任务1.获取ProductSku数据
        //  supplyAsync 无需参数，但是有返回结果
        CompletableFuture<ProductSku> productSkuCompletableFuture = CompletableFuture.supplyAsync(() -> {

            R<ProductSku> productSkuResult = remoteProductService.getProductSku(skuId, SecurityConstants.INNER);
            if (R.FAIL == productSkuResult.getCode()) {
                throw new ServiceException(productSkuResult.getMsg());
            }
            ProductSku productSku = productSkuResult.getData();
            itemVo.setProductSku(productSku);
            return productSku;
        }, threadPoolExecutor);


        //任务2.根据productId查询Product
        // thenAcceptAsync 需要有参数，无需返回结果
        CompletableFuture<Void> productCompletableFuture = productSkuCompletableFuture.thenAcceptAsync((productSku) -> {
            R<Product> productResult = remoteProductService.getProduct(productSku.getProductId(), SecurityConstants.INNER);
            if(R.FAIL == productResult.getCode()){
                throw new ServiceException(productResult.getMsg());
            }
            Product product = productResult.getData();
            itemVo.setProduct(product);
            //2.1 查询轮播图
            String sliderUrlsStr = product.getSliderUrls();
            String[] sliderUrlsStrArray = sliderUrlsStr.split(",");
            itemVo.setSliderUrlList(Arrays.asList(sliderUrlsStrArray));
            //2.2 获取商品规格信息
            //[{"key":"颜色","valueList":["白色","红色","黑色"]},{"key":"内存","valueList":["8G","18G"]}]
            String specValue = product.getSpecValue();
            JSONArray specValueJsonArray = JSON.parseArray(specValue);
            itemVo.setSpecValueList(specValueJsonArray);
        }, threadPoolExecutor);


        //任务3.根据skuId查询SkuPrice
        // runAsync 无需参数，无需返回结果。
        CompletableFuture<Void> skuPriceCompletableFuture = CompletableFuture.runAsync(() -> {
            R<SkuPrice> skuPriceResult = remoteProductService.getSkuPrice(skuId, SecurityConstants.INNER);
            if (R.FAIL == skuPriceResult.getCode()) {
                throw new ServiceException(skuPriceResult.getMsg());
            }
            SkuPrice skuPrice = skuPriceResult.getData();
            itemVo.setSkuPrice(skuPrice);
        }, threadPoolExecutor);


        //任务4.根据productId查询ProductDetails,可以获取到详情图片列表
        CompletableFuture<Void> productDetailsCompletableFuture = productSkuCompletableFuture.thenAcceptAsync((productSku) -> {
            R<ProductDetails> productDetailsResult = remoteProductService
                    .getProductDetails(productSku.getProductId(), SecurityConstants.INNER);
            if(R.FAIL == productDetailsResult.getCode()){
                throw new ServiceException(productDetailsResult.getMsg());
            }
            ProductDetails productDetails = productDetailsResult.getData();
            String imageUrls = productDetails.getImageUrls();
            String[] imageUrlsStrArray = imageUrls.split(",");
            itemVo.setDetailsImageUrlList(Arrays.asList(imageUrlsStrArray));
        }, threadPoolExecutor);


        //任务5.根据skuId查询SkuStockVo
        CompletableFuture<Void> skuStockCompletableFuture = CompletableFuture.runAsync(() -> {
            R<SkuStockVo> skuStockResult = remoteProductService.getSkuStock(skuId, SecurityConstants.INNER);
            if (R.FAIL == skuStockResult.getCode()) {
                throw new ServiceException(skuStockResult.getMsg()); // bug
            }
            SkuStockVo skuStockVo = skuStockResult.getData();
            itemVo.setSkuStockVo(skuStockVo);
        }, threadPoolExecutor);


        //任务6. 根据productId查询sku列表的数据，得到Map<String,Long>  规格对应skuId的Map集合
        CompletableFuture<Void> skuSpecValueMapCompletableFuture = productSkuCompletableFuture.thenAcceptAsync((productSku) -> {
            R<Map<String, Long>> skuSpecValueMapResult = remoteProductService.getSkuSpecValue(productSku.getProductId(), SecurityConstants.INNER);
            if (R.FAIL == skuSpecValueMapResult.getCode()) {
                throw new ServiceException(skuSpecValueMapResult.getMsg());
            }
            Map<String, Long> skuSpecValueMap = skuSpecValueMapResult.getData();
            itemVo.setSkuSpecValueMap(skuSpecValueMap);
        }, threadPoolExecutor);


        //用户浏览商品，记录历史  - 异步远程调用保存浏览记录（24小时只记录一次）。


        CompletableFuture.allOf(
                productSkuCompletableFuture,
                productCompletableFuture,
                skuPriceCompletableFuture,
                productDetailsCompletableFuture,
                skuStockCompletableFuture,
                skuSpecValueMapCompletableFuture
        ).join(); //阻塞等待6个异步任务结果回来，才能执行主线程。


        return itemVo;
    }
}
